<?php

namespace style\core;

use system\core\regex as rx;
use system\core\cache as cache;
use style\validator as validator;

Abstract class parser
{

	private static $currentNamespace = "*";
	private static $style;
	private $cssstream;
	private $rx_keywords = false;
	public static $sheet;

	function __construct($stream)
	{
		self::$style = new validator();
		$this->parse($stream);
		return $this;
	}

	public function refactor()
	{
//		print_r(self::$sheet);
		foreach( self::$sheet as $selector => $data )
		{
			$newSheet.= $selector."\n";
			$newSheet.= "{\n";
			foreach( $data["attributes"] as $attribute_name => $attribute_data )
			{
				if( $attribute_name !== "important" )
				{
					$newSheet.= "  ".$attribute_name.": ".$attribute_data["token"].";\n";
				}
			}
			$newSheet.= "}\n\n";
		}
		return $newSheet;
	}

	public function parse($stream)
	{
		$this->cssstream = $stream;
		$this->removeComments();
		$this->removeGlitches();
		$csslines = explode("\n", $this->cssstream);
		foreach( $csslines as $internalLinenumber => $cssRuleset )
		{
			$this->identifyRuleset($cssRuleset)."\n";
		}
	}

	private function identifyRuleset($string)
	{
		if( !trim($string) ) return false;
		switch (substr($string, 0, 1))
		{
			case "@":
				self::setCurrentNamespace($this->traceNamespace($string));
				return "NS_START";
				break;
			case "}":
				self::setCurrentNamespace("*");
				return "NS_END";
				break;
			default:
				$return = $this->createRuleset($string);
				//TODO Selector auf Existenz prüfen und ggf. Daten konsolidieren
				self::$sheet[$return["selector"]] = array("namespace" => self::$currentNamespace, "attributes" => $return["attributes"]);
				return "CSS";
				break;
		}
	}

	private function createRuleset($string)
	{
		preg_match('!(?<selector>[^\{]*)\{(?<stylerules>[^\{]*)\}!', $string, $match);
		unset($match[0]);
		unset($match[1]);
		unset($match[2]);
		$attributeset = $this->traceRuleset($match["stylerules"]);
//		print_r($ruleset);
//		echo json_encode($ruleset, JSON_FORCE_OBJECT);
		//print_r($match);
		return array("selector" => $match["selector"], "attributes" => $attributeset);
		//return $attributeset;
	}

	private function traceRuleset($string)
	{
		return $this->splitRules($string);
	}

	private function splitRules($string)
	{
		$array = explode(";", $string);
//		print_r($array);
		if( $array ) array_walk($array, array($this, 'trimRuleArray'));
		$array = $this->cleanupValues($array);
		if( $array ) $array = array_values($array);
//		print_r($array);
		$array = $this->consolidateAttributes($array);
//		print_r($array);
		return $array;
	}

	private function consolidateAttributes($array)
	{
//		echo "------------------------\n";
//		print_r($array);
		$newArray["important"] = array();
		if( $array ) foreach( $array as $itempos => $attribute )
			{
//			print_r($attribute);
				foreach( $attribute as $attribute_declaration => $attribute_data )
				{
//				echo $itempos."\n";
//				echo $attribute_declaration."\n";
//				print_r($attribute_data);
					if( $attribute_data["important"] )
					{
						$important = true;
						unset($attribute_data["important"]);
					}
					else
					{
						$important = false;
					}

					if( $attribute_data ) foreach( $attribute_data as $attr_key => $attr_val )
						{
//						echo "Append attribute: $attr_key\n";
							if( $important )
							{
								$newArray["important"][$attr_key] = $attr_val;
								if( !$newArray[$attr_key] )
								{
									$newArray[$attr_key] = $attr_val;
								}
							}
							else
							{
								$newArray[$attr_key] = $attr_val;
								if( $newArray["important"][$attr_key] )
								{
									$newArray[$attr_key] = $newArray["important"][$attr_key];
								}
							}
						}
				}
			}
//		print_r($newArray);
		return $newArray;
	}

	private function trimRuleArray(&$item, $key)
	{
		$item = trim($item);
		$item = $this->splitAttributePair($item);
//		echo $key."\n";
//		print_r($item);
	}

	private function splitAttributePair($pair)
	{
//		echo $pair."\n";
		list($attribute, $value) = explode(":", $pair, 2);
		$attribute = trim($attribute);
		$value = trim($value);
		if( !$attribute ) return NULL;

		return array($attribute => $this->removePolymorphism($attribute, $value));
//		return array("attribute" => $attribute, "value" => $this->removePolymorphism($attribute, $value), "raw_value" => $value);
	}

	/**
	 *
	 * @param type $attribute
	 * @param type $value
	 * @return type
	 * TODO: CLEANUP
	 */
	private function removePolymorphism($attribute, $value, $lastwalk = false)
	{
//		echo "".$attribute.""."[".$value."]\n";
		$rules = $this->getAttributeDefinition($attribute);
		if( $rules ) foreach( $rules as $rulekey => $rule )
			{
//				echo "Rule: ".$rule."\n";
				if( !($regex = cache::get($rule)) )
				{
//					echo "Attribute: ".$attribute."\n";
					$regex = $this->createRegexQuerys($rule);
//					echo "Current key: ".key($regex)."\n";
					$rxlist = array();
					if( $regex ) foreach( $regex as $rxkey => $rxstring )
						{
							$rxlist[] = $rxkey;
							$pattern["rxattrib"][$rulekey][$rxkey] = rx::o(rx::enumerate_storages(rx::o($rxstring), $this->rx_keywords));
						}
//					print_r($regex);
//					$regex = rx::t($regex);
//					$regex = rx::enumerate_storages($regex, true);
				}

//				$pattern[implode(" ", $rxlist)] = $regex;
//				echo $attribute.": ".$regex."\n";
			}
//		if( $pattern ) foreach( $pattern as $polykey => $rx )
//			{
//				preg_match("/".$rx."/i", $value, $matches);
//				print_r($matches);
//			}
		//Start the engines please!
		$attributes = $this->harvestAttributes($value, $pattern["rxattrib"]);
//		print_r($unsorted_attributes);
		$attributes = $this->cleanupValues($attributes, $lastwalk);
//		print_r($sorted_attributes);
		return $attributes;
		//return $pattern;
	}

	private function cleanupValues($attributearray, $lastwalk = false)
	{
		if( $attributearray ) foreach( $attributearray as $attribute_name => $attribute_data )
			{
				if( $attribute_data ) foreach( $attribute_data as $attribute_key => $attribute_value )
					{
						if( !is_numeric($attribute_key) || $attribute_key === 0 )
						{
							if( $attribute_key !== 0 )
							{
								list($attrid, $attrpos) = explode("_", $attribute_key);
								$newArray[$attribute_name][$attrid][$attrpos] = $attribute_value;
							}
							else
							{
								$newArray[$attribute_name]["token"][$attrpos] = $attribute_value;
							}
						}
					}
			}
		if( $newArray ) foreach( $newArray as $attribute_name => $attribute_data )
			{
				if( $newArray[$attribute_name] ) foreach( $newArray[$attribute_name] as $attribute_key => $attribute_value )
					{
						if( count($newArray[$attribute_name][$attribute_key]) == 1 )
						{
							$newArray[$attribute_name][$attribute_key] = current($newArray[$attribute_name][$attribute_key]);
						}
					}
				if( strpos($attribute_name, "|") !== false )
				{
					$expandedAttributes = explode("|", $attribute_name);
					foreach( $expandedAttributes as $exp_name )
					{
						$expandedArray[$exp_name] = $newArray[$attribute_name];
					}
				}
				else
				{
					if( $attribute_name != "important" && !$lastwalk && $newArray[$attribute_name]["token"] )
					{
//						echo "Remove Poly from: $attribute_name: ".$newArray[$attribute_name]["token"]."\n";
						$return = $this->removePolymorphism($attribute_name, $newArray[$attribute_name]["token"], true);
						if( $return ) foreach( $return as $solved_key => $solved_data )
							{
								$expandedArray[$solved_key] = $solved_data;
							}
					}
					else
					{
						//print_r($attribute_value);
						$expandedArray[$attribute_name] = $newArray[$attribute_name];
					}
				}
			}
		return $expandedArray;
	}

	private function harvestAttributes($valuestring, $matchsets)
	{
//		echo "Harvest from this: $valuestring\n";
		if( count($matchsets) > 1 )
		{
//			echo "Is polymorph!\n";
			$poly = true;
			krsort($matchsets);
		}
		else
		{
//			echo "Not polymorph!\n";
		}
//		print_r($matchsets);
		if( $matchsets ) foreach( $matchsets as $polykey => $attrib_matchset )
			{
				if( $attrib_matchset )
				{
//					print_r($attrib_matchset);
					$attrib_count = count($attrib_matchset) - 1;
					$current_attrib = 0;
					foreach( $attrib_matchset as $attrib_name => $attrib_rx_validator )
					{
						$current_attrib++;
						if( preg_match("!".$attrib_rx_validator."!is", $valuestring, $match, PREG_OFFSET_CAPTURE) )
						{
							$offset = $match[0][1];
							$strlen = strlen($match[0][0]);

							$match = rx::strip_offsets($match);
							$match = rx::array_clean($match);

							if( $this->rx_keywords ) $match = array_values($match);
							$matched_attribs[$attrib_name] = $match;
							$new_valuestring = substr_replace($valuestring, "", $offset, $strlen);

							$valuestring = $new_valuestring;
							/*
							  if( trim($new_valuestring) !== "" && $current_attrib != $attrib_count )
							  {
							  $valuestring = $new_valuestring;
							  }
							  elseif( trim($new_valuestring) == "" && $current_attrib != $attrib_count )
							  {
							  unset($matched_attribs);
							  }
							  else
							  {
							  //								echo "Done!";
							  return $matched_attribs;
							  }
							 */
						}

						if( $attrib_name != "important" && trim($valuestring) === "" && $poly === true )
						{

//								echo "Ran dry in alternativ $polykey attribute $attrib_name!\n";
//								echo "It IS ".($polykey - 1)."\n";
//								print_r($matchsets[($polykey)]);
//								print_r($matched_attribs);
							if( $matched_attribs["important"] ) $important = 1;
							foreach( $matched_attribs as $value )
							{
								$renamearray[] = $value;
							}
//								print_r($renamearray);
//								print_r($matchsets[$polykey]);
							foreach( $matchsets[$polykey] as $thename => $foo )
							{
								$renamecount++;
								if( $renamecount >= (2 - $important) )
								{
									$newarray[$thename] = $renamearray[$renamecount - (2 - $important)];
								}
							}
							return $newarray;
							//$matchsetscopy = $matchsets;
							//unset($matchsetscopy[$polykey]);
							//$this->harvestAttributes($valuestring, $matchsetscopy);
						}
					}
				}
			}
//		print_r($matched_attribs);
		return $matched_attribs;
	}

	private function getAttributeDefinition($attribute)
	{
		if( strpos($attribute, "|") !== false ) list($attribute) = explode("|", $attribute, 2);
//		echo "Attribute: ".$attribute."\n";
		$retrievedStyle = self::$style->getStyleDefinition($attribute);
		if( $retrievedStyle ) foreach( $retrievedStyle as $orderid => $definition )
			{
				$rules[] = $definition["rule"];
			}
		return $rules;
	}

	private function createRegexQuerys($rule, $formerDestination="")
	{
//		echo "Dive\n";
//		echo "Rule before Transform: ".$rule."\n";
		$fragments = $this->explodeRuleFragments($rule);
		array_unshift($fragments, "important:{<important>}");
//		print_r($fragments);
//		echo "FragmentDestination: $fragmentOptionList\n";
		foreach( $fragments as $fragmentPosition => $fragmentOptionPair )
		{
//			echo "Single Fragment: ".$fragmentOptionPair."\n";
			list($fragmentDestinationList, $fragmentOptionList) = explode(":", $fragmentOptionPair, 2);
//			echo "Destination: $fragmentDestinationList\n";
//							echo "Reached!\n";
			$fragmentOptionList = substr(trim($fragmentOptionList), 1, -1);
			if( !$fragmentOptionList )
			{
//				if( strpos($fragmentDestinationList, "|") !== false ) list($fragmentDestinationList) = explode("|", $fragmentDestinationList, 2);
				$tmp = $this->getAttributeDefinition($fragmentDestinationList);
				$fragmentOptionList = $tmp[0];
			}
//			echo "Send to transformation: $fragmentOptionList\n";
			if( strpos($fragmentOptionList, "{") !== false )
			{
//				echo "Retransform:\n";
//				echo "Unres Destination ".rx::c().": $fragmentDestinationList\n";
				$retransform = $this->createRegexQuerys($fragmentOptionList, $fragmentDestinationList);
//				print_r($retransform);
				if( is_array($retransform) ) foreach( $retransform as $fOL => $retransformed )
					{
//						echo "Destination2: $fOL\n";
//						echo "Retransformed: $retransformed\n";
						if( is_array($retransformed) )
						{
//							print_r($retransformed);
							$list[$fragmentDestinationList] = $retransformed;
						}
						else
						{
							$list[$fragmentDestinationList] = $this->transformToRegex($retransformed);
						}
					}
			}
			else
			{
//				echo "Former Destination: ".rx::c().": $formerDestination\n";
//				echo "Final Destination ".rx::c().": $fragmentDestinationList\n";
				if( $formerDestination ) $fragmentDestinationList = $formerDestination;
				$list[$fragmentDestinationList] = $this->transformToRegex($fragmentOptionList);
			}
		}
//		print_r($list);
		return $list;
//		print_r($fragments);
	}

	private function transformToRegex($optionlist)
	{
//		echo "Optionlist: ".$optionlist."\n";
		$options = explode("|", $optionlist);
		foreach( $options as $optionId => $optionTyp )
		{
			$resolved[] = $this->resolveOptionTyp($optionTyp);
//			echo "After Transform\n";
//			print_r($resolved);
//			echo "Resolved: ".$resolved."\n";
		}
		if( !$resolved )
		{
			throw new Exception("Unresolved optionTyp: $optionTyp");
		}
		return $resolved;
	}

	private function resolveOptionTyp($optionTyp)
	{
		if( $optionTyp[0] == "<" && $optionTyp[strlen($optionTyp) - 1] == ">" && strpos($optionTyp, ":") === false )
		{
			$resolved = $this->resolveOptionTypCommand($optionTyp);
			if( $resolved )
			{
				return $resolved;
			}
		}
		elseif( strpos($optionTyp, ":") === false )
		{
			$resolved = $this->resolveOptionTypKeyword($optionTyp);
			if( $resolved )
			{
				return $resolved;
			}
		}
		else
		{
//			echo "UNRESOLVED!\n".$optionTyp."\n";
//			print_r($this->createRegexQuerys($optionTyp));
			return "Something else twice! Baby";
		}
//		echo $optionTyp;
	}

	private function resolveOptionTypCommand($optionTyp)
	{
		$optionTyp = strtolower($optionTyp);

		if( cache::has($optionTyp) )
		{
			return cache::get($optionTyp);
		}

		$wspc = "[\s]*?";
//		$float = "[\d.]+";
		$float = "(?<float>\d*?\.+\d+|\d+)";
		$fnc = "[a-z0-9,\"' -]*"; //FontNameCharacter
		$sign = "(?<sign>[+-]?)";
//		$sign = "([+-]?)";
//		$number = "(?<number>".$float.")";
		$number = "(".$float.")";
		$unit_rel = "(?<unitrel>%|em|ex|px|gd|rem|vw|vh|vm|ch)";
//		$unit_rel = "(%|em|ex|px|gd|rem|vw|vh|vm|ch)";
		$unit_abs = "(?<unitabs>in|cm|mm|pt|pc)";
//		$unit_abs = "(in|cm|mm|pt|pc)";
		$unit_ang = "(?<unitang>deg|grad|rad|turn)";
//		$unit_ang = "(deg|grad|rad|turn)";
		$unit_tim = "(?<unittim>ms|s)";
//		$unit_tim = "(ms|s)";
		$unit_frq = "(?<unitfrq>hz|khz)";
//		$unit_frq = "(hz|khz)";
		$percent = "(?<percent>%)";
//		$percent = "(%)";
		$position = "(?<position>static|relative|absolute|fixed|inherit)";
//		$position = "(static|relative|absolute|fixed|inherit)";
		$offsetkeys = rx::o("top", "left", "right", "center", "middle", "bottom");
//		$boxoffset = "(?<boxoffset>)";
		$boxoffset = "(".$float.")";
		$color_hex = "(#[0-9abcdef]{3,6})";
		$color_rgb = "(rgb".$wspc."\(".$wspc."".$float."%?".$wspc.",".$wspc."".$float."%?".$wspc.",".$wspc."".$float."%?".$wspc."\))";
		$color_rgba = "(rgba".$wspc."\(".$wspc."".$float."%?".$wspc.",".$wspc."".$float."%?".$wspc.",".$wspc."".$float."%?".$wspc.",".$wspc."".$float."".$wspc."\))";
		$color_hsl = "(hsl".$wspc."\(".$wspc."".$float."".$wspc.",".$wspc."".$float."%".$wspc.",".$wspc."".$float."%".$wspc."\))";
		$color_keywords = array("antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "grey", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen");
		$color_specials = array("inherit", "transparent");
		$generic_font = array("serif", "sans-serif", "cursive", "fantasy", "monospace");
		$font_weight = array("normal", "bolder", "bold", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900");
		$sizekeys = array("small", "smaller", "normal", "large", "larger");

		//TODO Bei RECT Wert auto erlauben!
		$rect = "(rect".$wspc."\(".$wspc."".$float."|auto".$wspc.",".$wspc."".$float."".$wspc.",".$wspc."".$float."".$wspc.",".$wspc."".$float."".$wspc."\))";
//		$url_func = "(?:url".$wspc."\(".$wspc."['\"]?(?<url>[^'\"\)]*)['\"]?".$wspc."\))";
		$url_func = "(url".$wspc."\(".$wspc."['\"]?(?:[^'\"\)]*)['\"]?".$wspc."\))";

		switch ($optionTyp)
		{
			case "<length>":
			case "<width>":
				$rx = '(?<length>'.$sign.''.$number.''.rx::oo($unit_rel, $unit_abs).')';
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<integer>":
				$rx = '(?<integer>'.$sign.''.$number.')';
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<%>":
				return false;
				$rx = "([\d.]+\%)";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<string>":
				$rx = "(?<string>(?:\"(?:\\\\\"|[^\"])+\")|(?:'(?:\\\'|[^'])+'))";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<list>":
//				$rx = "(?<list>(?:[a-z0-9\"'-]* *,? *)*)?";
				$matchalist = "(?:(?:'".$fnc."')|(?:\"".$fnc."\")|[a-z0-9]*),(?:(?:'".$fnc."')|(?:\"".$fnc."\")|[a-z0-9,\"'-]*)*";
				$rx = "(?<list>".$matchalist.")";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<color>":
				rx::sortbylen($color_keywords, SORT_DESC);
				$color_keywords = "(?:".implode("|", $color_keywords).")";
				rx::sortbylen($color_specials, SORT_DESC);
				$color_specials = "(?:".implode("|", $color_specials).")";
				$rx = "(?<color>".rx::o($color_hex, $color_rgb, $color_rgba, $color_hsl, $color_specials, $color_keywords).")";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<sizekeys>":
				rx::sortbylen($sizekeys, SORT_DESC);
				$sizekeys = "(?:".implode("|", $sizekeys).")";
				$rx = "(?<sizekeys>".rx::o($sizekeys).")";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<fontweight>":
				rx::sortbylen($font_weight, SORT_DESC);
				$rx = "(?<fontweight>".rx::o($font_weight).")";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<fontname>":
				rx::sortbylen($generic_font, SORT_DESC);
				$rx = "(?<fontname>".rx::o($generic_font).")";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<position>":
				$rx = "(?<position>".$position.")";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<rect>":
				$rx = "(?<rect>".$rect.")";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<url>":
				$rx = "(?<urlfunc>".$url_func.")";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
			case "<important>":
				$rx = "(?<important>\!important)";
				cache::set($optionTyp, $rx);
				return $rx;
				break;
		}
		return false;
	}

	private function resolveOptionTypKeyword($optionTyp)
	{
		return "(?<keyword>".rx::q($optionTyp).")";
		//Obsolete
		switch ($optionTyp)
		{
			case "auto":
				return true;
				break;
			case "inherit":
				return true;
		}
		return false;
	}

	private function explodeRuleFragments($rule)
	{
		return explode(" ", $rule);
	}

	private function traceNamespace($string)
	{
		$string = substr($string, 1, -1);
		return $string;
	}

	private static function setCurrentNamespace($namespace = "*")
	{
		self::$currentNamespace = $namespace;
	}

	private function removeComments()
	{
		$this->cssstream = preg_replace('!/\*.*?\*/!ims', '', $this->cssstream);
	}

	private function removeGlitches()
	{
		$this->cssstream = preg_replace('![\s]+!s', ' ', $this->cssstream);
		$this->cssstream = preg_replace('!\s*{\s*!s', "{", $this->cssstream);
		$this->cssstream = preg_replace('!\s*}\s*!s', "}\n", $this->cssstream);
		$this->cssstream = preg_replace('!(\@[a-z ]*)\{!is', "\\1{\n", $this->cssstream);
		$this->cssstream = preg_replace('!, +!is', ",", $this->cssstream);
	}

	public static function load($css)
	{
		if( self::is_file($css) ) $stream = self::file($css);
		else $stream = self::stream($css);

		$thisClass = get_called_class();
		$cssObject = new $thisClass($stream);
		return $cssObject;
	}

	private static function stream($stream)
	{
		return $stream;
	}

	private static function is_file($filename)
	{
		if( !file_exists($filename) ) return;
		return true;
	}

	private static function file($filename)
	{
		return file_get_contents($filename);
	}

}

?>
